JavaScript 基础篇之数据类型与变量数据类型


###一、数据类型
1.Number
注意点:

  • 浮点数数值计算会存在舍入误差问题
  • NaN 不等于自身,判断 NaN 的方法只有 isNaN()
  • 数值转换 Number() 可适用于任何的数据类型,其中若果变量的值是 undefined ,则转换过来的值为 NaN ,String 类型中数值不含有效数字包括其他进制,转换回来也是 NaN

2.String

  • 特殊符号需要借助转义字符 ‘\’
  • 多行字符串可以使用反引号 `` 来表示。
  • 要获取字符串某个指定位置的字符,使用类似Array的下标操作,索引号从0开始
  • String.toUpperCase() 可以讲字符串转换成为大写,相反,String.toLowerCase() 可以将字符串转换成小写
  • indexOf() 会返回字符串出现的第一个位置
  • substring() 会返回检索区间的字符串

3.Boolean
false 与 true,说到布尔值,得扯一下比较符 == 与 ===
== 比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
而 === 比较,它不会自动转换数据类型,如果数据类型不一致,返回 false,如果一致,再比较。
由于 JavaScript 这个设计缺陷,不要使用 == 比较,始终坚持使用 === 比较。
例如:

1
2
3
4
false == 0; //true
false === 0;//false

1 / 3 === (1 - 2 / 3);// false ,上面提及的浮点数数值计算存在舍入问题,浮点数的比较也会存在这种问题

4.Undefined
使用 var 声明了变量,但还没初始化它时,那么这个变量的值就是 undefined ,undefined 仅仅在判断函数参数是否传递的情况下有用
5.Null
Null 只有 null 一个值,表示一个空对象的指针,如果变量准备用于报存对象,最好还是初始化为 null。
6.Object
可以通过 new 来创建,另外 object 实例都含有以下的属性和方法:

  • constructor 构造函数
  • hasOwnProperty(propertyName) 检查当前实例中的属性是否属于自己所有的还是继承的
  • isPrototypeof(object) 检查传入的对象是否是当前对象的原型
  • propertyIsEnumerable(propertyName) 检查给定的属性能否用 for-in 来枚举
  • toLocaleString() 返回对象的字符串表示,该字符串与执行环境的地区对应
  • toString() 返回对象的字符串表示
  • valueOf() 返回对象的字符串、数值或布尔值表示,通常与 toString() 返回值一致。

7.Symbol
Symbol 类型是 ES6 新增的一种数据类型:

  • 凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
  • Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。
  • Symbol 值不能与其他类型的值进行运算,会报错。但是,Symbol 值可以显式转为字符串。另外,Symbol 值也可以转为布尔值,但是不能转为数值。
  • 由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。

###二、变量数据类型
根据 ECMAScript ,JavaScript 变量可能包括两种不同数据类型的值:基本类型值与引用类型值,一般来说,上面我们提到的 Undefined、Null、Boolean、Number 和 String 归类为基本数据类型,而 Object 类型就是我们最常见的引用类型,那么,基本数据类型与引用类型有什么区别呢?
1、动态的属性
基本数据类型与引用类型在动态地添加属性上面具有不一样的表现,具体我们来见一下代码:
首先是基本数据类型:

1
2
3
var name = 'Eyesim';
name.age = 22;
alert(name.age);//undefined

然后再看引用数据类型:

1
2
3
var person  = new Object();
person.name = 'Eyesim';
alert(person.name);//EyesiM

由上面的两个例子可见,我们给字符串类型的 name 变量定义并赋值了一个 age 为 22 的属性,但是在下一行我们去访问这个 age 的属性的时候,发现这个属性不见了,但当我们给 person 对象添加了一个 name 为 Eyesim 的属性的时候,并在下一行去访问的时候是可以访问到 name 属性的,这说明了我们只能给引用类型值动态添加属性,以便将来使用。

2、复制变量值
复制变量值这一点在实际的开发中还是得注意,对于基本类型的变量,我们从一个变量向另一个变量复制基本类型值时,会在变量对象上创建一个新值,然后把该值复制到给新变量所分配的位置上面去,但使引用类型值并不是这样的,当引用类型的变量被另一个变量复制的时候,一方面也会将储存在变量对象中的值给复制到新变量所分配到的空间去,但不同的是什么呢?这个被复制的值实际上是一个指针,而这个指针指向存储在对中的一个对象,所以这个时候,新旧两个变量都是指向同一个地址,实际上引用的是同一个对象,因此改变其中任何一个变量,另一个变量也会跟着变化。下面我们来看一下具体是怎么样的:

1
2
3
4
5
6
7
8
//基本类型值的复制
var num1 = 2;
var num2 = num1;
alert(num1);//2
alert(num2);//2
num2 = 3;
alert(num1);//2
alert(num2);//3

1
2
3
4
5
6
7
var o1 = {
name:'Eyesim'
};
var o2 = o1;
o2.job = 'developer';
alert(o2.job);//developer
alert(o1.job);//developer

根据例子,基本类型值的复制,变量间的操作都是独立的,互不影响的,而引用类型值的变量复制,由于变量指向同一个对象,所以任何一个变量的操作都对其他变量造成影响。

3、传递参数
在 ECMAScript 中,所有函数的参数都是按值传递的,也就说,把函数外部的值复制给函数内部的参数,就和上面所说的变量的复制一样。

1
2
3
4
5
6
7
8
9
//基本数据类型的参数传递
function addTen(num) {
num += 10;
return num;
};
var count = 20;
var result = addTen(count);
alert(result);//30
alert(count);//20

1
2
3
4
5
6
function setName(obj) {
obj.name = "Eyesim";
}
var person = new Object();
setName(person);
alert(person.name);

这个结果与上面所说的变量复制是非常相似的,这是因为在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(参数),向参数传递引用类型的值时,会把这个值在内存中的地址给复制给局部变量,因此这个局部变量的变化会影响函数的外部的变量,所以说实际上,在传递参数上,引用类型与基本数据类型都是按值传递的。

4、检测类型
要检测一个变量是不是基本数据类型,是怎么检测的呢?JavaScript 给我们提供了 typeof 操作符,它可以确定变量是具体哪一种基本数据类型,但 typeof 操作符并不能判断引用类型是什么类型的对象,但是 ECMAScript 给我们提供了 intanceof 操作符来判断引用类型。另外,根据规定,所用引用类型的值都是 Object 的实例,因此在检测一个引用类型值和 Object 构造函数时, instanceof 操作符始终会返回 true,当然 instanceof 操作符在判断基本数据类型时总是返回 false,因为基本数据类型不是对象。